package com.jiale.ojsystem.judge;

import cn.hutool.json.JSONUtil;
import com.jiale.ojsystem.common.ErrorCode;
import com.jiale.ojsystem.exception.BusinessException;
import com.jiale.ojsystem.judge.codesandbox.CodeSandBox;
import com.jiale.ojsystem.judge.codesandbox.CodeSandBoxFactory;
import com.jiale.ojsystem.judge.codesandbox.CodeSandBoxProxy;
import com.jiale.ojsystem.judge.codesandbox.modle.ExecuteCodeRequest;
import com.jiale.ojsystem.judge.codesandbox.modle.ExecuteCodeResponse;
import com.jiale.ojsystem.model.dto.question.JudgeCase;
import com.jiale.ojsystem.model.dto.question.JudgeConfig;
import com.jiale.ojsystem.model.dto.questionsubmit.JudgeInfo;
import com.jiale.ojsystem.model.entity.Question;
import com.jiale.ojsystem.model.entity.QuestionSubmit;
import com.jiale.ojsystem.model.enums.QuestionSubmitResultEnum;
import com.jiale.ojsystem.service.QuestionService;
import com.jiale.ojsystem.service.QuestionSubmitService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 判题接口实现
 */
@Service
public class JudgeServiceImpl implements JudgeService {

    @Resource
    private QuestionSubmitService questionSubmitService;

    @Resource
    private QuestionService questionService;

    @Resource
    private JudgeStrategyManager judgeStrategyManager;

    @Override
    public QuestionSubmit doJudge(long questionSubmitId) {
        //获取题目提交记录
        QuestionSubmit questionSubmit = questionSubmitService.getById(questionSubmitId);
        if (questionSubmit == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "题目提交记录不存在");
        }
        Long questionId = questionSubmit.getQuestionId();
        Question question = questionService.getById(questionId);
        if (question == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "题目不存在");
        }
        questionSubmit.setJudgeStatus(0);
        //更新判题信息
        boolean update1 = questionSubmitService.updateById(questionSubmit);
        if (!update1) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "题目提交状态更新失败");
        }
        //搜集执行代码所需请求类的信息
        List<JudgeCase> judgeCaseList = JSONUtil.toList(question.getJudgeCase(), JudgeCase.class);
        List<String> inputList = judgeCaseList.stream().map(JudgeCase::getInput).collect(Collectors.toList());
        String language = questionSubmit.getLanguage();
        String code = questionSubmit.getCode();
        ExecuteCodeRequest executeCodeRequest = ExecuteCodeRequest.builder()
                .inputList(inputList)
                .code(code)
                .language(language)
                .build();
        //调用工厂模式和代理模式实现代码沙箱执行代码，得到执行结果
        CodeSandBoxFactory codeSandBoxFactory = new CodeSandBoxFactory();
        CodeSandBox codeSandBox = codeSandBoxFactory.doExecute("example");
        CodeSandBoxProxy codeSandBoxProxy = new CodeSandBoxProxy(codeSandBox);
        ExecuteCodeResponse executeCodeResponse = codeSandBoxProxy.doExecute(executeCodeRequest);
        long costedTime = executeCodeResponse.getCostedTime();
        long costMemory = executeCodeResponse.getCostMemory();
        JudgeInfo judgeInfo = new JudgeInfo();
        judgeInfo.setResult(QuestionSubmitResultEnum.WAITING.getValue());
        judgeInfo.setCostedTime(costedTime);
        judgeInfo.setCostedMemory(costMemory);
        questionSubmit.setJudgeInfo(JSONUtil.toJsonStr(judgeInfo));
        //更新判题信息
        boolean update2 = questionSubmitService.updateById(questionSubmit);
        if (!update2) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "题目提交状态更新失败");
        }
        //比较答题是否正确和规范
        JudgeConfig judgeConfig = JSONUtil.toBean(question.getJudgeConfig(), JudgeConfig.class);
        JudgeContext judgeContext=new JudgeContext();
        judgeContext.setJudgeConfig(judgeConfig);
        judgeContext.setOutputList(executeCodeResponse.getOutputList());
        judgeContext.setInputList(inputList);
        judgeContext.setJudgeInfo(judgeInfo);
        judgeContext.setJudgeCaseList(judgeCaseList);
        judgeContext.setQuestionSubmit(questionSubmit);
        judgeContext.setCostedTime(costedTime);
        judgeContext.setCostedMemory(costMemory);
        judgeContext.setLanguage(language);
        judgeInfo = judgeStrategyManager.doJudge(judgeContext);
        questionSubmit.setJudgeInfo(JSONUtil.toJsonStr(judgeInfo));
        //更新判题信息
        boolean update6 = questionSubmitService.updateById(questionSubmit);
        if (!update6) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "题目提交状态更新失败");
        }
        return questionSubmit;
    }
}
